package org.tinygroup.dbrouterjdbc3.jdbc;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.tinygroup.dbrouterjdbc3.jdbc.ShardsFilter.ShardFilterData;

/**
 * TinyResultSetSimple的建造者
 * 
 * @author renhui
 * 
 */
public class ResultSetSimpleBuilder {
	private String schema;

	private String catalog;
	private static final String COLUMN_NAME = "COLUMN_NAME";
	private static final String TABLE_NAME = "TABLE_NAME";
	private static final String TABLE_SCHEM = "TABLE_SCHEM";
	private static final String TABLE_CAT = "TABLE_CAT";
	private TinyResultSetSimple simple = new TinyResultSetSimple();

	private ValueSetting valueSetting;

	public ResultSetSimpleBuilder(String schema, String catalog) {
		super();
		this.schema = schema;
		this.catalog = catalog;
	}

	public static ResultSetSimpleBuilder getTablesBuilder(String schema,
			String catalog) {
		ResultSetSimpleBuilder builder = new ResultSetSimpleBuilder(schema,
				catalog);
		builder.setValueSetting(builder.new GetTablesValueSetting());
		return builder;
	}

	public static ResultSetSimpleBuilder getColumnsBuilder(String schema,
			String catalog) {
		ResultSetSimpleBuilder builder = new ResultSetSimpleBuilder(schema,
				catalog);
		builder.setValueSetting(builder.new GetColumnsValueSetting());
		return builder;
	}

	public static ResultSetSimpleBuilder getPrimaryKeysBuilder(String schema,
			String catalog) {
		ResultSetSimpleBuilder builder = new ResultSetSimpleBuilder(schema,
				catalog);
		builder.setValueSetting(builder.new GetPrimaryKeysValueSetting());
		return builder;
	}

	public ValueSetting getValueSetting() {
		return valueSetting;
	}

	public void setValueSetting(ValueSetting valueSetting) {
		this.valueSetting = valueSetting;
	}

	public void addColumns(ResultSetMetaData metaData) throws SQLException {
		int columnCount = metaData.getColumnCount();
		for (int index = 1; index <= columnCount; index++) {
			String name = metaData.getColumnName(index);
			simple.addColumn(index, name, metaData.getColumnType(index),
					metaData.getPrecision(index), metaData.getScale(index));

		}
	}

	public void addValues(int columnCount, ResultSet resultSet,
			List<ShardFilterData> datas) throws SQLException {
		valueSetting.addValues(columnCount, resultSet, datas);
	}

	private String getFilterData(String value, List<ShardFilterData> datas) {
		for (ShardFilterData filterData : datas) {
			if (filterData.containKey(value)) {
				return filterData.get(value);
			}
		}
		return null;
	}

	public TinyResultSetSimple build() {
		return simple;
	}

	/**
	 * 添加resultset值的接口
	 * 
	 * @author renhui
	 * 
	 */
	interface ValueSetting {
		public void addValues(int columnCount, ResultSet resultSet,
				List<ShardFilterData> datas) throws SQLException;

	}

	abstract class AbstractValueSetting implements ValueSetting {
		protected Map<String, Boolean> tableNameCaches = new HashMap<String, Boolean>();
		protected Map<String, Boolean> columnNameCaches = new HashMap<String, Boolean>();

		public void addValues(int columnCount, ResultSet resultSet,
				List<ShardFilterData> datas) throws SQLException {
			while (resultSet.next()) {
				String tableValue = resultSet.getString(TABLE_NAME);
				String columnValue = getColumnValue(resultSet);
				String logicTableValue = getFilterData(tableValue, datas);
				if (logicTableValue == null
						|| isRepeat(logicTableValue, columnValue)) {
					continue;
				}
				Object[] values = new Object[columnCount];
				for (int index = 0; index < columnCount; index++) {
					String name = resultSet.getMetaData().getColumnName(
							index + 1);
					if (name.equals(TABLE_NAME)) {
						values[index] = logicTableValue;
					} else if (name.equals(TABLE_SCHEM)) {
						values[index] = schema;
					} else if (name.equals(TABLE_CAT)) {
						values[index] = catalog;
					} else {
						values[index] = resultSet.getObject(index + 1);
					}
				}
				simple.addRow(values);
				tableNameCaches.put(logicTableValue, true);
				columnNameCaches.put(columnValue, true);
			}
		}

		protected String getColumnValue(ResultSet resultSet)
				throws SQLException {
			return resultSet.getString(COLUMN_NAME);
		}

		/**
		 * 认为参数值是否已经重复，在getTables方法中，如果caches中已经存在filterData，则认为是重复数据。
		 * 
		 * @param filterData
		 * @return
		 */
		protected boolean isRepeat(String filterData, String columnValue) {
			return false;
		}

	}

	public class GetTablesValueSetting extends AbstractValueSetting {
		@Override
		protected boolean isRepeat(String filterData, String columnValue) {
			return tableNameCaches.get(filterData) == Boolean.TRUE;
		}

		protected String getColumnValue(ResultSet resultSet)
				throws SQLException {
			return null;
		}
	}

	class GetColumnsValueSetting extends AbstractValueSetting {
		@Override
		protected boolean isRepeat(String filterData, String columnValue) {
			return columnNameCaches.get(columnValue) == Boolean.TRUE;
		}
	}

	class GetPrimaryKeysValueSetting extends AbstractValueSetting {
		@Override
		protected boolean isRepeat(String filterData, String columnValue) {
			return columnNameCaches.get(columnValue) == Boolean.TRUE;
		}
	}

}
